home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / program / cppnl012.zip / cppnl012.txt next >
Text File  |  1996-06-28  |  12KB  |  413 lines

  1. Issue #012
  2. June, 1996
  3.  
  4.  
  5. Contents:
  6.  
  7. New Language Feature - Mutable
  8. Introduction to Templates Part 4 - Specializations
  9. Using C++ as a Better C Part 12 - Function Parameter Names
  10. Performance - Duplicate Inlines
  11.  
  12.  
  13. NEW LANGUAGE FEATURE - MUTABLE
  14.  
  15. In C++ it's possible to have a class object instance that is constant
  16. and cannot be modified by the program, once initially set up.  For
  17. example:
  18.  
  19.         class A {
  20.         public:
  21.                 int x;
  22.                 A();
  23.         };
  24.  
  25.         const A a;
  26.  
  27.         void g()
  28.         {
  29.                 a.x = 37;
  30.         }
  31.  
  32. is illegal.  In a similar way, invoking a non-const member function on
  33. a const object is also illegal:
  34.  
  35.         class A {
  36.         public:
  37.                 int x;
  38.                 A();
  39.                 void f();
  40.         };
  41.  
  42.         const A a;
  43.  
  44.         void g()
  45.         {
  46.                 a.f();
  47.         }
  48.  
  49. The reason for this latter prohibition is due to separate
  50. compilation.  A::f() may be defined in some other translation unit,
  51. and there's no way of knowing whether it modifies the object upon
  52. which it operates.
  53.  
  54. It is possible to define const member functions:
  55.  
  56.         void f() const;
  57.  
  58. that are allowed to operate on a const object instance.  Such a
  59. function does not modify the instance it operates on.  The type of the
  60. "this" pointer for a class T is normally:
  61.  
  62.         T *const this;
  63.  
  64. meaning that the pointer cannot be changed.  Within a const member
  65. function, the type is:
  66.  
  67.         const T *const this;
  68.  
  69. meaning that neither the pointer nor the pointed-at object instance
  70. can be modified.
  71.  
  72. Recently a new feature has been added to C++ to selectively allow for
  73. individual data class members to be modified even for a const object
  74. instance, and lessen the need for casting away of const.  For example:
  75.  
  76.         class A {
  77.         public:
  78.                 mutable int x;
  79.                 A();
  80.         };
  81.  
  82.         const A a;
  83.  
  84.         void f()
  85.         {
  86.                 a.x = 37;
  87.         }
  88.  
  89. This says that "x" can be modified even though it's a member of a
  90. const object instance.
  91.  
  92. How useful "mutable" turns out to be remains to be seen.  One cited
  93. example for its use is within classes whose object instances appear
  94. constant but actually do change their state internally.  For example:
  95.  
  96.         class Box {
  97.                 double xll, yll;        // lower left X,Y
  98.                 double xur, yur;        // upper right X,Y
  99.                 double a;               // cached area
  100.         public:
  101.                 double area() const
  102.                 {
  103.                         a = (xur - xll) * (yur - yll);
  104.                         return a;
  105.                 }
  106.                 class Box(double x1, double y1, double x2, double y2) :
  107.                     xll(x1), yll(y1), xur(x2), yur(y2)
  108.                 {
  109.                 }
  110.         };
  111.  
  112.         const Box b(1.0, 1.0, 11.0, 14.0);
  113.  
  114.         void f()
  115.         {
  116.                 b.area();
  117.         }
  118.  
  119. which is illegal usage unless we instead say:
  120.  
  121.         class Box {
  122.                 double xll, yll;        // lower left X,Y
  123.                 double xur, yur;        // upper right X,Y
  124.                 mutable double a;       // cached area
  125.         public:
  126.                 double area() const
  127.                 {
  128.                         a = (xur - xll) * (yur - yll);
  129.                         return a;
  130.                 }
  131.                 class Box(double x1, double y1, double x2, double y2) :
  132.                     xll(x1), yll(y1), xur(x2), yur(y2)
  133.                 {
  134.                 }
  135.         };
  136.  
  137.         const Box b(1.0, 1.0, 11.0, 14.0);
  138.  
  139.         void f()
  140.         {
  141.                 b.area();
  142.         }
  143.  
  144.  
  145. INTRODUCTION TO TEMPLATES PART 4 - SPECIALIZATIONS
  146.  
  147. In previous issues we've covered some of the basics of C++ templates.
  148. Recall that a template is a class or function skeleton, and is
  149. combined with specified type arguments to produce an actual class or
  150. function.
  151.  
  152. Beyond this general mechanism, C++ also allows the programmer to
  153. define specialized classes and functions that take the template and
  154. implement it for particular types of template arguments.
  155.  
  156. Suppose, for example, that you have a String template, that supports
  157. strings of most anything -- chars, ints, doubles, arbitrary class
  158. types, and so on.  Now, it's pretty likely that strings of characters
  159. will be used heavily, so it might make sense to special case this
  160. combination of template and template argument:
  161.  
  162.         template <class T> class String {
  163.                 // stuff
  164.         };
  165.  
  166.         template <> class String<char> {
  167.                 // stuff
  168.         };
  169.  
  170.         String<char> x;
  171.  
  172. The "template <>" notation is fairly new and may not yet be
  173. implemented in your local compiler.
  174.  
  175. This sequence is a bit different from:
  176.  
  177.         template <class T> class String {
  178.                 // stuff
  179.         };
  180.  
  181.         String<char> x;
  182.  
  183. In this second case, the default implementation of String is used,
  184. whereas in the specialization case, the programmer overrides the
  185. default template and provides an implementation of String<char>.
  186.  
  187. For a function template, a specialization would be defined as:
  188.  
  189.         template <class T> void f(T) {}
  190.  
  191.         template <> void f(int) {}
  192.  
  193. It's also possible to have forward declarations of specializations:
  194.  
  195.         template <class T> class String {};
  196.  
  197.         template <> class String<double>;
  198.  
  199. or:
  200.  
  201.         template <class T> void f(T) {}
  202.  
  203.         template <> void f(unsigned short&);
  204.  
  205. A specialization must be declared or defined before use, so for
  206. example:
  207.  
  208.         template <class T> int f(T) {return 0;}
  209.  
  210.         int i = f(12.34);
  211.  
  212.         template <> int f(double) {return 37;}
  213.  
  214. is invalid.
  215.  
  216. An interesting quirk with function templates concerns the case where
  217. you have a C function, mixed in with a function template and
  218. specialization:
  219.  
  220.         extern "C" void f(int);
  221.  
  222.         template <class T> int f(T) {return 0;}
  223.  
  224.         template <> int f(int)
  225.         {
  226.                 f(37);
  227.                 return 0;
  228.         }
  229.  
  230. The f(37) call here is not recursive.  Both "void f(int)" and "int
  231. f(int)" match the call, and the non-template is preferred in such a
  232. case.
  233.  
  234. It's also possible to have nested specializations, as in:
  235.  
  236.         template <class T> class A {
  237.                 template <class U> class B {
  238.                         template <class V> void f(V) {}
  239.                 };
  240.         };
  241.  
  242.         template <> template <> template <>
  243.                 void A<float>::B<double>::f(long double) {}
  244.  
  245. and you can specialize special member types such as constructors:
  246.  
  247.         struct A {
  248.                 template <class T> A(T) {}
  249.         };
  250.  
  251.         template <> A::A(short) {}
  252.  
  253. or static data members:
  254.  
  255.         template <class T> struct A {
  256.                 template <class U> struct B {
  257.                         static int x;
  258.                 };
  259.         };
  260.  
  261.         template <> template <> int A<float>::B<long double>::x = 59;
  262.  
  263. Specializations are a way of special-casing templates for particular
  264. argument types, and are useful in a variety of applications.  But they
  265. can also be abused and make code harder to understand, especially if a
  266. reader of the code doesn't pick up on the fact that specializations
  267. are present.
  268.  
  269.  
  270. USING C++ AS A BETTER C PART 12 - FUNCTION PARAMETER NAMES
  271.  
  272. Suppose that you have a C++ function, and for some reason you don't
  273. actually use all the function parameters:
  274.  
  275.         int sum(int a, int b, int c)
  276.         {
  277.                 return a + b;   // c not used
  278.         }
  279.  
  280. Many compilers will give a warning in this case to the effect
  281. "warning: parameter c not used".  This is perfectly legal code but the
  282. warning can be tedious to deal with.
  283.  
  284. C++ has a feature that allows you to simply omit the parameter name:
  285.  
  286.         int sum(int a, int b, int)
  287.         {
  288.                 return a + b;
  289.         }
  290.  
  291. and avoid the warning.  This feature is especially handy when stubbing
  292. out code.  A similar feature exists in catch handlers used in
  293. exception handling.
  294.  
  295.  
  296. PERFORMANCE - DUPLICATE INLINES
  297.  
  298. Suppose that you have a bit of code such as:
  299.  
  300.         inline long fact(long n)
  301.         {
  302.                 if (n < 2)
  303.                         return 1;
  304.                 else
  305.                         return n * fact(n - 1);
  306.         }
  307.  
  308.         int main()
  309.         {
  310.                 lon